home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Chans / uucp / uucp_out.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  13.6 KB  |  631 lines

  1. /* uucp_out.c: uucp outbound channel */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/uucp/RCS/uucp_out.c,v 6.0 1991/12/18 20:13:06 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Chans/uucp/RCS/uucp_out.c,v 6.0 1991/12/18 20:13:06 jpo Rel $
  9.  *
  10.  * $Log: uucp_out.c,v $
  11.  * Revision 6.0  1991/12/18  20:13:06  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "util.h"
  19. #include "head.h"
  20. #include "qmgr.h"
  21. #include "q.h"
  22. #include "dr.h"
  23. #include "prm.h"
  24. #include <isode/cmd_srch.h>
  25. #include    <sys/stat.h>
  26. #include    <fcntl.h>
  27. #include    <sys/wait.h>
  28. #include    <signal.h>
  29.  
  30. #ifdef __STDC__
  31. #define VOLATILE volatile
  32. #else
  33. #define VOLATILE
  34. #endif
  35.  
  36. #ifndef WCOREDUMP
  37. #define WCOREDUMP(x) (((union wait *)&(x))->w_coredump)
  38. #endif
  39. #ifndef WEXITSTATUS
  40. #define WEXITSTATUS(x) (((union wait *)&(x)) -> w_retcode)
  41. #endif
  42. #ifndef WTERMSIG
  43. #define WTERMSIG(x) (((union wait *)&(x)) -> w_termsig)
  44. #endif
  45.  
  46. extern char    *quedfldir,
  47.         *chndfldir,
  48.         *logdfldir,
  49.         *hdr_822_bp;
  50.  
  51. extern CHAN     *ch_nm2struct();
  52. extern    char    *loc_dom_mta;
  53. extern int    rfc8222uu();
  54. CHAN         *mychan;
  55. char        *this_msg = NULL, *this_chan = NULL;
  56. char        *myhostname;
  57. char        *uuxstr;
  58. int        first_successDR;
  59.  
  60. static struct type_Qmgr_DeliveryStatus *process();
  61. static void set_success();
  62. static void dirinit();
  63. static ADDR *getnthrecip();
  64. static jmp_buf    toplevel;
  65. static int   pipe_signaled;
  66. static int data_bytes;
  67. static int initialise();
  68.  
  69. static int processMsg(), doProcess(), send_to_child();
  70. /* ARGSUSED */
  71. static SFD sig_pipe(sig)
  72. int sig;
  73. {
  74.     pipe_signaled = TRUE;
  75.     longjmp (toplevel, DONE);
  76. }
  77.  
  78. /*   */
  79. /* main routine */
  80.  
  81. main (argc, argv)
  82. int     argc;
  83. char    **argv;
  84. {
  85.     sys_init (argv[0]);
  86.     dirinit();
  87. #ifdef PP_DEBUG
  88.     if (argc>1 && (strcmp (argv[1],"debug") == 0))
  89.         debug_channel_control (argc,argv,initialise,process, NULLIFP);
  90.     else
  91. #endif
  92.         channel_control (argc, argv, initialise, process, NULLIFP);
  93. }
  94.  
  95. /*   */
  96. /* routine to move to correct place in file system */
  97.  
  98. static void dirinit()
  99. {
  100.     if (chdir (quedfldir) < 0)
  101.         err_abrt (RP_LIO, " Unable to change directory to '%s'",
  102.               quedfldir);
  103. }
  104.  
  105. /*   */
  106.  
  107. static CMD_TABLE uucptbl[] = {
  108. #define TBL_UUXCMD 1
  109.     "uux",    TBL_UUXCMD,
  110. #define TBL_HOST 2
  111.     "host",    TBL_HOST,
  112.     0, -1
  113.     };
  114.  
  115. /* channel initialise routine */
  116.  
  117. static int initialise (arg)
  118. struct type_Qmgr_Channel *arg;
  119. {
  120.     char *name, *p;
  121.     char    *argv[20];
  122.     int    i, argc;
  123.     char    buffer[BUFSIZ];
  124.  
  125.     if (uuxstr) free (uuxstr);
  126.     uuxstr = NULLCP;
  127.     if (myhostname) free (myhostname);
  128.     myhostname = NULLCP;
  129.  
  130.     name = qb2str (arg);
  131.  
  132.     if ((mychan = ch_nm2struct (name)) == NULLCHAN) {
  133.         PP_OPER (NULLCP, ("Chan/uucp_out : Channel '%s' not known",name));
  134.         if (name != NULL) free (name);
  135.         return NOTOK;
  136.     }
  137.  
  138.     if (mychan -> ch_out_info == NULLCP) {
  139.         PP_OPER (NULLCP, ("%s channel (%s) has no info parameter",
  140.                   mychan -> ch_name, mychan -> ch_show));
  141.         return NOTOK;
  142.     }
  143.     (void) strcpy (buffer, mychan -> ch_out_info);
  144.     if ((argc = sstr2arg (buffer, 20, argv, ",")) <= 0) {
  145.         PP_LOG (LLOG_EXCEPTIONS, ("Info string unparseable"));
  146.         return NOTOK;
  147.     }
  148.  
  149.     for (i = 0; i < argc; i++) {
  150.         if ((p = index (argv[i], '=')) == NULL) {
  151.             PP_LOG (LLOG_EXCEPTIONS,
  152.                 ("Info string for %s not in key=val format",
  153.                  mychan -> ch_name));
  154.             return NOTOK;
  155.         }
  156.         *p++ = '\0';
  157.         switch (cmd_srch (argv[i], uucptbl)) {
  158.             case TBL_UUXCMD:
  159.             uuxstr = strdup (p);
  160.             break;
  161.  
  162.             case TBL_HOST:
  163.             myhostname = strdup (p);
  164.             break;
  165.  
  166.             default:
  167.             PP_LOG (LLOG_EXCEPTIONS,
  168.                 ("Unknown key in chan info for %s '%s'",
  169.                  mychan -> ch_name,
  170.                  argv[i]));
  171.             return NOTOK;
  172.         }
  173.     }
  174.     if (uuxstr == NULLCP) {
  175.         PP_LOG (LLOG_EXCEPTIONS, ("uux not set in info"));
  176.         return NOTOK;
  177.     }
  178.     if (myhostname == NULLCP)
  179.         myhostname = strdup (loc_dom_mta);
  180.  
  181.     (void) signal (SIGCHLD, SIG_DFL);
  182.     if (name != NULL) free (name);
  183.     return OK;
  184. }
  185.  
  186. /*   */
  187. /* routine to check if allowed to filter this message through this channel */
  188. static int security_check (msg)
  189. struct type_Qmgr_ProcMsg *msg;
  190. {
  191.      char         *msg_file = NULL, *msg_chan = NULL;
  192.     int        result;
  193.  
  194.     result = TRUE;
  195.     msg_file = qb2str (msg->qid);    
  196.     msg_chan = qb2str (msg->channel);
  197.  
  198.     if ((mychan == NULLCHAN) || (strcmp (msg_chan,mychan->ch_name) != 0)) {
  199.         PP_LOG (LLOG_EXCEPTIONS,
  200.                ("Chans/shell channel err: '%s'",msg_chan));
  201.         result = FALSE;
  202.     }
  203.  
  204.     /* free all storage used */
  205.     if (msg_file != NULL) free (msg_file);
  206.     if (msg_chan != NULL) free (msg_chan);
  207.     return result;
  208. }
  209.  
  210. /*   */
  211. /* routine called to do uucp */
  212.  
  213. static struct type_Qmgr_DeliveryStatus *process (arg)
  214. struct type_Qmgr_ProcMsg *arg;
  215. {
  216.     struct prm_vars    prm;
  217.     Q_struct    que;
  218.     ADDR        *sender = NULL;
  219.     ADDR        *recips = NULL;
  220.     int         rcount, retval;
  221.     struct type_Qmgr_UserList     *ix;
  222.     ADDR                *adr;
  223.     char        *realfrom = NULL;
  224.     bzero ((char *) &que,sizeof (que));
  225.     bzero ((char *) &prm,sizeof (prm));
  226.  
  227.     delivery_init (arg->users);
  228.     delivery_setall (int_Qmgr_status_messageFailure);
  229.     first_successDR = TRUE;
  230.  
  231.     if (security_check (arg) != TRUE)
  232.         return deliverystate;
  233.  
  234.     if (this_msg != NULL) free (this_msg);
  235.     if (this_chan != NULL) free (this_chan);
  236.  
  237.     this_msg = qb2str (arg->qid);
  238.     this_chan = qb2str (arg->channel);
  239.  
  240.     PP_LOG (LLOG_NOTICE,
  241.            ("%s processing msg '%s'",mychan->ch_name,this_msg));
  242.  
  243.     if (rp_isbad (rd_msg (this_msg,&prm,&que,&sender,&recips,&rcount))) {
  244.         PP_LOG (LLOG_EXCEPTIONS,
  245.                ("%s rd_msg err: '%s'",mychan->ch_name,this_msg));
  246.         rd_end();
  247.         return deliverystate;
  248.     }
  249.  
  250.         
  251.     if (getrealfrom (sender, &realfrom) != OK) {
  252.         PP_LOG (LLOG_EXCEPTIONS,
  253.                ("%s unable to construct real sender message for orig of message '%s'",mychan->ch_name,this_msg));
  254.         rd_end();
  255.         return deliverystate;
  256.     }
  257.  
  258.     if (arg->users == NULL)
  259.         PP_LOG (LLOG_NOTICE,
  260.             ("%s : passed a NULL user list for message '%s'",
  261.             mychan->ch_name,
  262.             this_msg));
  263.  
  264.     /* check each recipient for processing */
  265.     for (ix = arg->users; ix; ix = ix->next) {
  266.         if ((adr = getnthrecip (&que,(int)ix->RecipientId->parm)) == NULL) {
  267.             PP_LOG (LLOG_EXCEPTIONS,
  268.                   ("%s : failed to find recipient %d of msg '%s'",mychan->ch_name,ix->RecipientId->parm, this_msg));
  269.             delivery_set ((int)ix->RecipientId->parm, int_Qmgr_status_messageFailure);
  270.             continue;
  271.         }
  272.  
  273.         switch (chan_acheck (adr, mychan, 1, NULLVP)) {
  274.             case OK:
  275.             if (processMsg (this_msg,adr, realfrom) == NOTOK) {
  276.                 PP_LOG (LLOG_EXCEPTIONS,
  277.                        ("%s : failed to process msg '%s' for recip '%d' on channel '%s'",mychan->ch_name,this_msg, adr->ad_no, this_chan));
  278.                 delivery_set (adr->ad_no, int_Qmgr_status_messageFailure);
  279.             } else {
  280.                 PP_LOG (LLOG_NOTICE,
  281.                      ("%s : processed '%s' for recipient %d",mychan->ch_name,this_msg,adr->ad_no));
  282.                 set_success (adr, &que, this_msg);
  283.             }
  284.             break;
  285.             default:
  286.             break;
  287.         }
  288.     }
  289.  
  290.     if (rp_isbad (retval = wr_q2dr (&que, this_msg))) {
  291.         PP_LOG (LLOG_EXCEPTIONS,
  292.                ("%s wr_q2dr failure '%d'",mychan->ch_name,retval));
  293.         delivery_resetDRs (int_Qmgr_status_messageFailure);
  294.     }
  295.  
  296.     rd_end();
  297.     if (realfrom != NULL) free (realfrom);
  298.     return deliverystate;
  299. }
  300.  
  301. static void set_success (recip, que, msg)
  302. ADDR        *recip;
  303. Q_struct    *que;
  304. char        *msg;
  305. {
  306.     if (recip->ad_usrreq == AD_USR_CONFIRM ||
  307.         recip->ad_mtarreq == AD_MTA_CONFIRM ||
  308.         recip->ad_mtarreq == AD_MTA_AUDIT_CONFIRM) {
  309.         set_1dr (que, recip->ad_no, this_msg,
  310.              DRR_NO_REASON, -1, NULLCP);
  311.         delivery_set (recip->ad_no, 
  312.                  (first_successDR == TRUE) ? int_Qmgr_status_positiveDR : int_Qmgr_status_successSharedDR);
  313.     } else {
  314.         (void) wr_ad_status (recip, AD_STAT_DONE);
  315.         (void) wr_stat (recip, que, this_msg, data_bytes);
  316.         delivery_set (recip->ad_no, int_Qmgr_status_success);
  317.     }
  318. }
  319.  
  320. /*   */
  321. static int processMsg (msg,recip, realfrom)
  322. /* returns OK if managed to process msg for recip on mychan */
  323. char    *msg;
  324. ADDR     *recip;
  325. char    *realfrom;
  326. {
  327.     char     *origdir = NULL,
  328.         *cmdline = NULL;
  329.     int result = OK;
  330.  
  331.     if (qid2dir (msg, recip, TRUE, &origdir) != OK) {
  332.         PP_LOG (LLOG_EXCEPTIONS,
  333.                ("%s original directory not found for recipient %d of message '%s'",mychan->ch_name,recip->ad_no, msg));
  334.         result = NOTOK;
  335.     }
  336.  
  337.     if (result == OK &&
  338.         mychan->ch_out_info == NULL) {
  339.         PP_OPER (NULLCP,
  340.              ("%s uux pathname not given in info string",mychan->ch_name));
  341.         result = NOTOK;
  342.     }
  343.  
  344.     if (result == OK && 
  345.         rfc8222uu (recip->ad_outchan->li_mta,recip->ad_r822adr, &cmdline) != OK) {
  346.         PP_LOG (LLOG_EXCEPTIONS,
  347.                ("%s unable to convert to uucp format address of recip %d of message '%s'",mychan->ch_name,recip->ad_no, msg));
  348.         result = NOTOK;
  349.     }
  350.         
  351.     if ((result == OK) && (doProcess (origdir,msg, cmdline, realfrom) != OK))
  352.         result = NOTOK;
  353.  
  354.     if (origdir != NULL) free (origdir);
  355.     if (cmdline != NULL) free (cmdline);
  356.     return result;
  357. }
  358.  
  359. /*   */
  360.  
  361. static int sigpiped, sigalarmed;
  362. static SFD alarmed(), piped();
  363. static jmp_buf pipe_alrm_jmp;
  364.  
  365. static int doProcess (orig, msg, cmdline, realfrom)
  366. /* processes orig directory contents through mychan */
  367. char    *orig,    /* original directory */
  368.     *msg,    /* message */
  369.     *cmdline,/* uucp cmdline */
  370.     *realfrom;/* real sender */
  371. {
  372.     int    fd[2],
  373.         result = OK,
  374.         pid,
  375.         pgmresult,
  376.         margc;
  377.     char    *program = NULL,
  378.         *margv[20];
  379.     SFP     oldalarm, oldpipe;
  380.     VOLATILE int    killed = 0;
  381.     struct stat statbuf;
  382.  
  383.     if (pipe (fd) != 0) {
  384.         PP_LOG (LLOG_EXCEPTIONS,
  385.                ("%s pipe failed",mychan->ch_name));
  386.         return NOTOK;
  387.     }
  388.  
  389.     if ((margc = sstr2arg (cmdline, 20, margv, " \t")) < 1) 
  390.         return NOTOK;
  391.         
  392.     if (margv[0][0] == '/')
  393.         /* given full path name */
  394.         program = strdup (margv[0]);
  395.     else {
  396.         program = (char *) malloc ((unsigned int) (strlen (chndfldir) + 1 + strlen (margv[0]) + 1));
  397.         (void) sprintf (program,"%s/%s",chndfldir,margv[0]);
  398.     }
  399.     
  400.     if (stat (program, &statbuf) != OK) {
  401.         PP_OPER (NULLCP,
  402.              ("%s : missing uux program '%s'",mychan -> ch_name, program));
  403.         return NOTOK;
  404.     }
  405.     if ((pid = tryfork()) == 0) {
  406.         /* in child so redirect in- and out-put */
  407.         (void) dup2 (fd[0], 0);
  408.         (void) close (fd[0]);
  409.         (void) close (fd[1]);
  410.         (void) setpgrp (0, getpid());
  411.  
  412.         (void) execv (program,margv);
  413.         _exit (1);
  414.     } else if (pid == -1) {
  415.         PP_LOG (LLOG_EXCEPTIONS,
  416.                ("%s: tryfork failed for msg %s",
  417.                mychan->ch_name,this_msg));
  418.         (void) close (fd[1]);
  419.         result = NOTOK;
  420.     } else {
  421. #ifdef SYS5
  422.         int w;
  423. #else
  424.         union wait w;
  425. #endif
  426.  
  427.         oldalarm = signal (SIGALRM, alarmed);
  428.         oldpipe = signal (SIGPIPE, piped);
  429.         sigpiped = 0;
  430.         sigalarmed = 0;
  431.         data_bytes = 0;
  432.  
  433.         if (setjmp (pipe_alrm_jmp) != DONE) {
  434.             if (send_to_child (orig, fd[1], realfrom) == NOTOK)
  435.                 result = NOTOK;
  436.             (void) close (fd[1]);
  437.         } else {
  438.             if (sigalarmed)
  439.                 PP_TRACE (("alarm went off"));
  440.             if (sigpiped)
  441.                 PP_TRACE (("pipe went off"));
  442.         }
  443.  
  444.         if (sigpiped) { /* pipe died - reset for timeout */
  445.             sigpiped = 0;
  446.             if (setjmp (pipe_alrm_jmp) == DONE)
  447.                 PP_TRACE (("Timeout"));
  448.         }
  449.  
  450.         if (sigalarmed) { /* alarm went off */
  451.             PP_NOTICE (("Process taking too long ... killing"));
  452.             killed = 1;
  453.             (void) killpg (pid, SIGTERM);
  454.             sleep (2);
  455.             (void) killpg (pid, SIGKILL);
  456.         }
  457.  
  458. #ifdef SYS5
  459.         while ((pgmresult = wait (&w)) != pid &&
  460.                pgmresult != -1)
  461. #else
  462.         while ((pgmresult = wait (&w.w_status)) != pid &&
  463.                pgmresult != -1)
  464. #endif
  465.             PP_TRACE (("process %d returned", pgmresult));
  466.  
  467.         PP_TRACE (("pid %d returned term=%d, retcode=%d core = %d killed = %d",
  468.               pid, WTERMSIG(w), WEXITSTATUS(w),
  469.               WCOREDUMP(w), killed));
  470.         (void) alarm (0);
  471.  
  472.         (void) signal (SIGPIPE, oldpipe);
  473.         (void) signal (SIGALRM, oldalarm);
  474.  
  475.         if ((pgmresult == pid) && (WEXITSTATUS(w) == 0) && (killed == 0))
  476.             result = OK;
  477.         else 
  478.             result = NOTOK;
  479.     }
  480.     (void) close (fd[0]);
  481.  
  482.     return result;
  483. }
  484.  
  485. /* ARGSUSED */
  486. static SFD alarmed(sig)
  487. int sig;
  488. {
  489.     sigalarmed = 1;
  490.     longjmp (pipe_alrm_jmp, DONE);
  491. }
  492.  
  493. /* ARGSUSED */
  494. static SFD piped(sig)
  495. int sig;
  496. {
  497.     sigpiped = 1;
  498.     longjmp (pipe_alrm_jmp, DONE);
  499. }
  500.  
  501. /*   */
  502. static int write_to_child (file, fd_out)
  503. char    *file;
  504. int    fd_out;
  505. {
  506.     char    buf[BUFSIZ];
  507.     int    fd_in,
  508.         num;
  509.  
  510.     if ((fd_in = open (file, O_RDONLY, 0666)) == -1) {
  511.         PP_LOG (LLOG_EXCEPTIONS,
  512.                ("%s input file err '%s'",mychan->ch_name, file));
  513.         return NOTOK;
  514.     }
  515.  
  516.     while ((num = read (fd_in, buf, BUFSIZ)) > 0) {
  517.         if (write (fd_out, buf, num) == -1) {
  518.             close (fd_out);
  519.             return NOTOK;
  520.         }
  521.         data_bytes += num;
  522.     }
  523.     close (fd_in);
  524.     return OK;
  525. }
  526.                
  527. static ADDR *getnthrecip (que, num)
  528. Q_struct    *que;
  529. int        num;
  530. {
  531.     ADDR *ix = que->Raddress;
  532.  
  533.     if (num == 0)
  534.         return que->Oaddress;
  535.     while ((ix != NULL) && (ix->ad_no < num))
  536.         ix = ix->ad_next;
  537.     return ix;
  538. }
  539.  
  540. static LIST_RCHAN *getnthchannel (chans,num)
  541. LIST_RCHAN    *chans;
  542. int        num;
  543. {
  544.     LIST_RCHAN    *ix = chans;
  545.     int        icount = 0;
  546.  
  547.     while ((ix != NULL) && (icount++ < num)) 
  548.         ix = ix->li_next;
  549.  
  550.     return ix;
  551. }
  552.  
  553. static char    *get_adrstr (adr)
  554. ADDR    *adr;
  555. {
  556.     char    *key;
  557.     switch (adr->ad_type) {
  558.         case AD_X400_TYPE:
  559.         key = adr->ad_r400adr;
  560.         break;
  561.         case AD_822_TYPE:
  562.         key = adr->ad_r822adr;
  563.         break;
  564.         default:
  565.         key = adr->ad_value;
  566.         break;
  567.     }
  568.     return key;
  569. }
  570.  
  571. static int is822hdr (file)
  572. char    *file;
  573. {
  574.     char *ix = rindex (file, '/');
  575.  
  576.     if (ix == NULL
  577.         || (strncmp ((ix+1),hdr_822_bp,strlen (hdr_822_bp)) != 0))
  578.         return FALSE;
  579.     else
  580.         return TRUE;
  581. }
  582.  
  583. static int send_to_child (orig, fd, realfrom)
  584. char    *orig;
  585. int    fd;
  586. char    *realfrom;
  587. {
  588.     char    file[MAXPATHLENGTH];
  589.     SFP    old_sig;
  590.     char    buf[BUFSIZ];
  591.     time_t    timenow;
  592.     int    len;
  593.  
  594.     (void) time (&timenow);
  595.     
  596.     msg_rinit (orig);
  597.  
  598.     pipe_signaled = FALSE;
  599.  
  600.     /* set signal handler */
  601.     old_sig = signal (SIGPIPE, sig_pipe);
  602.  
  603.     /* set long jump */
  604.     setjmp (toplevel);
  605.     (void) sprintf (buf, "From %s %.24s remote from %s\n",
  606.             realfrom, ctime (&timenow), myhostname);
  607.     len = strlen (buf);
  608.     if (write (fd, buf, len) != len)
  609.         return NOTOK;
  610.     data_bytes += len;
  611.  
  612.     while (pipe_signaled == FALSE
  613.            && msg_rfile (file) == RP_OK) {
  614.         if (write_to_child (file, fd) == NOTOK) {
  615.             msg_rend ();
  616.             return NOTOK;
  617.         }
  618.         if (is822hdr (file) == TRUE) {
  619.             if (write (fd, "\n", 1) != 1)
  620.                 return NOTOK;
  621.             data_bytes ++;
  622.         }
  623.     }
  624.     
  625.     msg_rend();
  626.  
  627.     /* unset signal handler */
  628.     (void) signal (SIGPIPE, old_sig);
  629.     return OK;
  630. }
  631.